/*  
 *  ACEConsole.cs - Text UI for playing against ACE.
 * 
 *  Copyright(c) 2007 Adam W Adair
 *
 *  This file is part of Adam's Chess Engine (ACE).
 *
 *  ACE is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *   
 *  ACE is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with ACE; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
using System;
using System.Collections.Generic;
using System.Text;
using ACE.Board;
using ACE.Engine;

namespace ACE
{
    class ACEConsole
    {
        private const string PROMPT="ace> ";
        ChessGame game;

        public ACEConsole()
        {
            game = new ChessGame();
            game.init();
        }

        public void RunMeSomeMoreHey()
        {
            Console.WriteLine("\nType 'help' for a list of commands\n");
            for (; ; )
            {
                try
                {
                    if (game.IsComputerTurn())
                        ComputerMove();

                    Console.Out.Write(PROMPT);
                    string response = Console.In.ReadLine();
                    string[] tokens = response.Split(" ".ToCharArray());
                    if (tokens.Length == 0) continue;
                    switch (tokens[0])
                    {
                        case "": continue;
                        case "?":
                        case "help":
                            DisplayHelp();
                            break;
                        case "exit":
                        case "quit":
                        case "bye":
                            Exit(0);
                            break;
                        case "new":
                            game.init();
                            break;
                        case "bd":
                            Console.WriteLine(game.Board.ToString());
                            break;
                        case "uci":
                            GotoUCIMode();
                            break;
                        case "on":
                            game.TurnOnComputerPlayer();
                            break;
                        case "off":
                            game.TurnOffComputerPlayer();
                            break;
                        case "fen":
                            FEN(response);
                            break;
                        case "undo":
                            game.Undo();
                            break;
                        case "debug":
                            //Turn on the super secret debug mode
                            DebugOn();
                            break;
                        case "eval":
                            ShowEval();
                            break;
                        default:
                            move(response);
                            break;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }

        /// <summary>
        /// Attempt to make a move.
        /// </summary>
        /// <param name="command"></param>
        private void move(string command)
        {
            game.TryMove(command);
            Log.DefaultLog.LogDebug("Player played: " + command);
            if (PrintStatus())
            {
                game.TurnOffComputerPlayer();
            }
        }

        private void DebugOn()
        {
            Log.DefaultLog.Level = Log.LogLevel.LOG_ERROR | Log.LogLevel.LOG_WARNING |
                                        Log.LogLevel.LOG_INFO | Log.LogLevel.LOG_DEBUG;
            Log.DefaultLog.LogDebug("Debug mode turned on.");
        }

        private void ComputerMove()
        {
            Move move = game.ComputerPlay();
            string szMove = ChessBoard.GetCoordinate(move.From) + ChessBoard.GetCoordinate(move.To);
            Console.WriteLine("Computer played: " + szMove);
            Log.DefaultLog.LogDebug("Computer played: " + szMove);
            if (PrintStatus())
            {
                game.TurnOffComputerPlayer();
            }
        }

        private bool PrintStatus()
        {
            ChessGame.GameStatus status = game.Status;
            switch (status)
            {
                case ChessGame.GameStatus.PLAYING:
                    return false;
                case ChessGame.GameStatus.WHITE_MATE:
                    Console.WriteLine("1-0 (White mates)");
                    return true;
                case ChessGame.GameStatus.BLACK_MATE:
                    Console.WriteLine("0-1 (Black mates)");
                    return true;
                case ChessGame.GameStatus.STALEMATE:
                    Console.WriteLine("1/2-1/2 (Stalemate)");
                    return true;
                case ChessGame.GameStatus.FIFTY_MOVE_DRAW:
                    Console.WriteLine("1/2-1/2 (draw by fifty move rule)");
                    return true;
                case ChessGame.GameStatus.REPETITION_DRAW:
                    Console.WriteLine("1/2-1/2 (draw by repetition)");
                    return true;
                default:
                    break;
            }
            return false;
        }

        /// <summary>
        /// Put the engine in UCI mode to play with Chess applications.
        /// </summary>
        private void GotoUCIMode()
        {
            UCIConsole uci = new UCIConsole(game);
            uci.RunMe();
        }

        public void DisplayHelp()
        {
            Console.WriteLine("on - computer plays for the side to move");
            Console.WriteLine("off - computer stops playing");
            Console.WriteLine("new - starts a new game");
            Console.WriteLine("fen <fen string> - sets up position of board with FEN string");
            Console.WriteLine("bd - display the board");
            Console.WriteLine("bye - exit the program");
            Console.WriteLine("uci - switch to Universal Console Interface mode");
            Console.WriteLine("<move> - move in coordinate notation. example: e2e4 or e7e8q (promote to queen)");
        }

        private void FEN(string req)
        {
            if (req.StartsWith("fen "))
            {
                string fen = req.Substring(4);
                game.FEN_Position(fen);
            }
            else
            {
                Console.WriteLine("Invalid fen command.");
            }
        }

        public void Exit(int value)
        {
            if(value==0){
                Console.WriteLine("Good-bye.");
            }
            System.Environment.Exit(value);
        }

        void ShowEval()
        {
            BoardEvaluator be = new BoardEvaluator(game.Board);
            int white = be.Evaluate(0);
            int black = be.Evaluate(1);
            Console.Out.WriteLine("White=" + white + "  Black=" + black+"\n");
        }

    }
}
